﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Basmus.DataStructures.Generic;

namespace Basmus.Reflection
{
	public static class Reflection
	{
		public static IEnumerable<IGrouping<PropertyInfo, TAttribute>> PropertiesWithMultipleAttribute<TAttribute>(this Type type, bool inherit)
			where TAttribute : Attribute
		{
			return type.GetProperties().MembersWithMultipleAttribute<PropertyInfo, TAttribute>(inherit);
		}

		public static IEnumerable<IGrouping<TMemberInfo, TAttribute>> MembersWithMultipleAttribute<TMemberInfo,TAttribute>(this IEnumerable<TMemberInfo> members, bool inherit)
			where TAttribute : Attribute
			where TMemberInfo:MemberInfo
		{
			foreach (TMemberInfo member in members)
			{
				IEnumerable<TAttribute> attrs = member.GetCustomAttributes(typeof(TAttribute), inherit).Cast<TAttribute>();
				if (attrs.Count() > 0)
				{
					yield return attrs.ToGroup(member);
				}
			}
		}

		public static IEnumerable<Pair<PropertyInfo, TAttribute>> PropertiesWithNonMultipleAttribute<TAttribute>(this Type type, bool inherit)
			where TAttribute : Attribute
		{
			return type.GetProperties().MembersWithNonMultipleAttribute<PropertyInfo, TAttribute>(inherit);
		}

		public static IEnumerable<Pair<TMemberInfo, TAttribute>> MembersWithNonMultipleAttribute<TMemberInfo,TAttribute>(this IEnumerable<TMemberInfo> members, bool inherit)
			where TAttribute:Attribute
			where TMemberInfo:MemberInfo
		{
			foreach (TMemberInfo member in members)
			{
				IEnumerable<TAttribute> attrs = member.GetCustomAttributes(typeof(TAttribute), inherit).Cast<TAttribute>();
				if (attrs.Count() > 0)
				{
					yield return new Pair<TMemberInfo, TAttribute> { First = member, Second = attrs.First() };
				}
			}
		}
		public static bool IEnumerableImplemented(this Type type, out Type IEnumerableTypeArgument)
		{
			if (type.Name == "IEnumerable`1")
			{
				IEnumerableTypeArgument = type.GetGenericArguments()[0];
				return true;
			}
			else
			{
				Type inter = type.GetInterface("IEnumerable`1", true);
				if (inter != null)
				{
					IEnumerableTypeArgument = inter.GetGenericArguments()[0];
					return true;
				}
				else
				{
					IEnumerableTypeArgument = type;
					return false;
				}
			}
		}
	}
}
